package baseObject;

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

import baseObject.IRectObj.eHitType;

public class BrickBreaker implements IBrickBreaker{

	protected IPaddle paddle;
	protected IWall wall;
	protected IBall ball;
	protected TMove tMove;
	protected TFinished tFinished;

	protected ArrayList<IBrickBreakerObserver> observersArrayList;
	protected boolean printTrace = false;

	public BrickBreaker(int xMax, int yMax){
		this.init(xMax, yMax);
	}
	
	public BrickBreaker() {
		this.init(IBrickBreaker.XMAX, IBrickBreaker.YMAX);
	}

	@Override
	public void init(int xMax, int yMax) {
		this.paddle = BaseObjectsFactory.newPaddle((IBrickBreaker.XMAX / 2) - (100/2), IBrickBreaker.YMAX - 50,100,10);
		this.ball = BaseObjectsFactory.newBall((IBrickBreaker.XMAX / 2), ((IBrickBreaker.YMAX - 50) - 10) ,10,10);
		this.tFinished = TFinished.NO;
		this.tMove = TMove.NONE;
		this.observersArrayList = new ArrayList<IBrickBreakerObserver>();		
	}

	public void initLevelOne(){
		this.wall = BaseObjectsFactory.newWall();
		int xStep = 0;
		int yStep = 0;
		int cpt = 0;
		Random rand = new Random(10);
		IBrick brick;
		while(cpt < 50){
			if(cpt%10 == 0 && cpt != 0){
				yStep += 10;
				xStep = 0;
			}
			int randCurrent = rand.nextInt() % 10;
			brick = BaseObjectsFactory.newBrick(xStep, yStep,50,10);
			if(randCurrent == cpt%7){
				brick.setBreakeable(false);
			}else{
				brick.setBreakeable(true);
			}
			brick.setResistance(1);
			wall.addBrick(brick);
			xStep += 50;
			cpt++;

		}
		this.notifyEnvironmentChange();
	}

	public void calculateStep() {
		this.moveBall();
		
		if(this.getPlayerDirection() == TMove.LEFT)
			this.paddle.left();
		
		if(this.getPlayerDirection() == TMove.RIGHT)
			this.paddle.right();
		
		this.setPlayerDirection(TMove.NONE);
		
		if(this.ball.getX() == 0){
			if(this.ball.getDeltaX() == -1){
				this.ball.invertDirection(true, false);
			}
		}else if(this.ball.getX() == this.getXMAX()){
			if(this.ball.getDeltaX() == 1){
				this.ball.invertDirection(true, false);
			}
		}


		if(this.ball.getY() == 0){
			if(this.ball.getDeltaY() == -1){
				this.ball.invertDirection(false, true);
			}
		}else if(this.ball.getY() == this.getYMAX()){
			if(this.ball.getDeltaY() == 1){
				this.ball.invertDirection(false, true);
			}
		}

		CopyOnWriteArrayList<IBrick> affectedBrick = this.wall.getListBrickHit(this.ball);
		for(IBrick brick : affectedBrick){
			if(brick.getResistance() > 0){
				if(printTrace){
					System.out.println("Affected brick");
					System.out.println("Resistance = " + brick.getResistance());
				}
			}
			this.ball.invertDirection(false, true);
		}

		CopyOnWriteArrayList<IBrick> getAllBrick = this.wall.getListBrick();
		for(IBrick b: getAllBrick){
			if(!b.isBreakable()){
				if(b.getHitState(this.ball) != eHitType.NO){
					this.ball.invertDirection(false, true);
				}
			}
		}
		eHitType paddleHit = this.paddle.getHitState(this.ball);
		if(paddleHit != eHitType.NO){
			if(printTrace)
				System.out.println("hit paddle");
			this.ball.invertDirection(false, true);
		}

		if(this.ball.getY() > this.paddle.getY() && this.ball.getX() != this.paddle.getX()){
			tFinished = TFinished.GAMEOVER;
			if(printTrace)
				System.out.println("GAMEOVER");
		}

		if(this.wall.getListBrickBreakeable().isEmpty()){
			tFinished = TFinished.WIN;
			if(printTrace)
				System.out.println("YOU WIN");
		}
		
		this.notifyEnvironmentChange();
	}

	public void movePaddle(TMove tMove) {
		switch (tMove) {
		case LEFT:
			this.paddle.left();
			break;
		case RIGHT:
			this.paddle.right();
			break;
		case NONE:
			break;
		}
		this.notifyEnvironmentChange();
	}

	public int getXMAX() {
		return IBrickBreaker.XMAX;
	}


	public int getYMAX() {
		return IBrickBreaker.YMAX;
	}


	public TFinished isFinished() {
		return tFinished;
	}



	public IPaddle getPaddle() {
		return paddle;
	}


	public IWall getWall() {
		return wall;
	}


	public IBall getBall() {
		return ball;
	}


	public void moveBall() {
		this.ball.move();
	}

	public void addIBrickBreakerObserver(
			IBrickBreakerObserver brickBreakerObserver) {
		this.observersArrayList.add(brickBreakerObserver);
	}

	public void notifyEnvironmentChange() {
		for(IBrickBreakerObserver observer: this.observersArrayList){
			observer.changeEnvironment(this);
		}
	}

	public synchronized void setPlayerDirection(TMove direction) {
		this.tMove = direction;
	}
	
	public synchronized TMove getPlayerDirection() {
		return tMove;
	}


}
